/*
Copyright (C) 1996-1997 GX Media, Inc.
Copyright (C) 2010 Ronie Salgado

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

*/

#include "stdafx.h"
#include <GL/glext.h>
#include <GL/glu.h>
#include "QDraw.h"
#include "QDrawOGL.h"
#include "QView.h"
#include "Game.h"

struct GLLine
{
	float x1, y1, x2, y2;
	float r, g, b;
};

typedef std::vector<GLLine> GLLines;

struct GLTriangle
{
	float x[3], y[3], z[3];
	float s[3], t[3];
	float n[3];
	float r, g, b;
	Texture *texture;
};
typedef std::vector<GLTriangle> GLTriangles;

struct GLNormal
{
	float nf[3];
	float nv[3];
};

typedef std::vector<GLNormal> GLNormals;

struct GLVertex
{
	float x, y, z;
	float nx, ny, nz;
	float r, g, b;
	float s, t;
};

typedef std::vector<GLVertex> GLVertices;

struct GLObject
{
	int startIndex;
	int numVertices;
	Matrix44 modelViewMatrix;
	GLenum mode;
	Texture *texture;
};

typedef std::vector<GLObject> GLObjects;
typedef std::vector<unsigned short> GLIndices;

// QGLCanvas implementation.
class QGLCanvas: public wxGLCanvas
{
public:
	QGLCanvas(wxWindow *parent, QDrawOpenGL *draw);
	~QGLCanvas();

	void OnPaint(wxPaintEvent &event);
	void OnSize(wxSizeEvent &event);

	void Initialize();
	void Render();
	void CheckTexture(Texture *texture);

	virtual bool ProcessEvent(wxEvent& event);

	GLLines lines;
	GLTriangles triangles;
	GLNormals normals;

	GLVertices vertices;
	GLIndices indices;
	GLObjects objects;
	QDrawOpenGL *draw;

	bool initialized;

	// OpenGL extensions.
	bool EXT_texture_compression_s3tc;
	PFNGLMULTTRANSPOSEMATRIXFPROC glMultTransposeMatrixf;
	PFNGLDRAWRANGEELEMENTSEXTPROC glDrawRangeElementsEXT;

	DECLARE_EVENT_TABLE();
private:
	void DrawWireframe();
	void DrawSolid();
	void DrawTextured();
	void DrawLines();

	void DrawObjects();
	void ChangeTexture(Texture *newTexture);
	void EnableBasicLighting();
	void DisableBasicLighting();

	Texture *lastTexture;
};

BEGIN_EVENT_TABLE(QGLCanvas, wxGLCanvas)
	EVT_PAINT(QGLCanvas::OnPaint)
	EVT_SIZE(QGLCanvas::OnSize)
END_EVENT_TABLE()

static int attribList[] =
{
	WX_GL_DOUBLEBUFFER,
	WX_GL_RGBA,
	WX_GL_MIN_RED, 5,
	WX_GL_MIN_GREEN, 5,
	WX_GL_MIN_BLUE, 5,
	WX_GL_MIN_ALPHA, 5,
	WX_GL_DEPTH_SIZE, 24,
	0, 0
};

QGLCanvas::QGLCanvas(wxWindow *parent, QDrawOpenGL *draw)
	: wxGLCanvas(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0, wxT("GLCanvas"), attribList), draw(draw)
{
	initialized = false;
	EXT_texture_compression_s3tc = false;
	glMultTransposeMatrixf = NULL;
	glDrawRangeElementsEXT = NULL;
}

QGLCanvas::~QGLCanvas()
{
}

void QGLCanvas::OnPaint(wxPaintEvent &event)
{
	wxPaintDC dc(this);
	Render();
}

void QGLCanvas::OnSize(wxSizeEvent &event)
{
	SetCurrent();

	wxSize size = event.GetSize();
	glViewport(0, 0, size.GetWidth(), size.GetHeight());

	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();

	glOrtho(0.0f, (GLfloat)size.GetWidth(), (GLfloat)size.GetHeight(), 0.0f, -1.0f, 1.0f);

	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();

	glDepthFunc(GL_LEQUAL);

	// Setup lighting
	float direction[4] = {0.0, 0.0, 1.0, 0.0};
	float diffuse[4] = {1.0, 1.0, 1.0, 1.0};
	float ambient[4] = {0.2, 0.2, 0.2, 1.0};
	glEnable(GL_LIGHT0);
	glEnable(GL_COLOR_MATERIAL);
	glLightfv(GL_LIGHT0, GL_POSITION, direction);
	glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
	glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambient);
	glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
}

inline void *glGetProcAddress(const char *proc)
{
#ifdef _WIN32
	return (void*)wglGetProcAddress(proc);
#else
	return (void*)glXGetProcAddress((const GLubyte*)proc);
#endif
}

void QGLCanvas::Initialize()
{
	initialized = true;

	// Check for extensions.
	const char *extensions = (const char*)glGetString(GL_EXTENSIONS);

	// Texture compression.
	if(strstr(extensions, "EXT_texture_compression_s3tc") != NULL)
	{
		EXT_texture_compression_s3tc = true;
	}
	
	glMultTransposeMatrixf = (PFNGLMULTTRANSPOSEMATRIXFPROC)glGetProcAddress("glMultTransposeMatrixf");
	glDrawRangeElementsEXT = (PFNGLDRAWRANGEELEMENTSEXTPROC)glGetProcAddress("glDrawRangeElementsEXT");
}

// Transform qoole coordinates into opengl.
static GLfloat qooleMatrix[] =
{
	1.0f, 0.0f, 0.0f, 0.0f,
	0.0f, 0.0f, -1.0f, 0.0f,
	0.0f, 1.0f, 0.0f, 0.0f,
	0.0f, 0.0f, 0.0f, 1.0f,
};

void QGLCanvas::Render()
{
	SetCurrent();
	
	if(!initialized)
		Initialize();

	float bg = 57.0f/255.0f;
	glClearColor(bg, bg, bg, 0.0);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
	glHint(GL_LINE_SMOOTH_HINT,GL_NICEST);
	glLineWidth(1.0f);

	// Old Rendering
	if(draw->renderMode == QView::RT_WIREFRAME)
		DrawWireframe();
	else if(draw->renderMode == QView::RT_SOLID)
		DrawSolid();
	else if(draw->renderMode == QView::RT_TEXTURED ||
			draw->renderMode == QView::RT_SHADED)
		DrawTextured();

	// Draw Lines.
	DrawLines();

	// Draw objects.
	// New rendering.
	DrawObjects();

	SwapBuffers();
}

void QGLCanvas::DrawWireframe()
{
	size_t numlines = lines.size();
	if(numlines == 0)
		return;

	glDisable(GL_DEPTH_TEST);
	glDisable(GL_TEXTURE_2D);
	glDisable(GL_LIGHTING);

	glEnable(GL_LINE_SMOOTH);
	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	glHint(GL_LINE_SMOOTH_HINT,GL_NICEST);

	glBegin(GL_LINES);

	for(size_t i = 0; i < numlines; i++)
	{
		GLLine &line = lines[i];
		glColor3f(line.r, line.g, line.b);
		glVertex2f(line.x1, line.y1);
		glVertex2f(line.x2, line.y2);
	}

	glEnd();
}

void QGLCanvas::DrawSolid()
{
	size_t numtris = triangles.size();
	if(numtris == 0)
		return;

	glEnable(GL_DEPTH_TEST);
	glEnable(GL_LIGHTING);
	glDisable(GL_TEXTURE_2D);

	glBegin(GL_TRIANGLES);

	for(int i = 0; i < numtris; i++)
	{
		GLTriangle &tri = triangles[i];
		glColor3f(tri.r, tri.g, tri.b);
		for(int j = 0; j < 3; j++)
		{
			glVertex3f(tri.x[j], tri.y[j], tri.z[j]);
		}
	}

	glEnd();
}

void QGLCanvas::DrawTextured()
{
	size_t numtris = triangles.size();
	if(numtris == 0)
		return;

	int i, j;

	glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
	glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

	glEnable(GL_DEPTH_TEST);
	glEnable(GL_TEXTURE_2D);
	glEnable(GL_LIGHTING);

	glCullFace(GL_FRONT);
	glEnable(GL_CULL_FACE);

	for(int i = 0; i < numtris; i++)
	{
		GLTriangle &tri = triangles[i];
		Texture *texture = tri.texture;
		if(!texture)
		{
			glDisable(GL_TEXTURE_2D);
			glBegin(GL_TRIANGLES);
			glColor3f(tri.r, tri.g, tri.b);
			for(int j = 0; j < 3; j++)
				glVertex3f(tri.x[j], tri.y[j], tri.z[j]);
			glEnd();
			glEnable(GL_TEXTURE_2D);
			continue;
		}

		// Check if the texture is valid.
		CheckTexture(texture);

		glBindTexture(GL_TEXTURE_2D, texture->tInfo);

		glBegin(GL_TRIANGLES);

		glNormal3fv(normals[i].nf);
		for(j = 0; j < 3; j++)
		{
			glTexCoord4f(tri.s[j], tri.t[j], 0.0f, tri.z[j]);
			glVertex3f(tri.x[j], tri.y[j], tri.z[j]);
		}

		glEnd();
	}

	glEnd();
}

void QGLCanvas::DrawLines()
{
	size_t numlines = lines.size();
	if(numlines > 0 && draw->renderMode != QView::RT_WIREFRAME)
	{
		glDisable(GL_DEPTH_TEST);
		glDisable(GL_TEXTURE_2D);
		glDisable(GL_LIGHTING);

		glEnable(GL_LINE_SMOOTH);
		glEnable(GL_BLEND);
		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

		glBegin(GL_LINES);

		for(size_t i = 0; i < numlines; i++)
		{
			GLLine &line = lines[i];
			glColor3f(line.r, line.g, line.b);
			glVertex2f(line.x1, line.y1);
			glVertex2f(line.x2, line.y2);
		}

		glEnd();
	}
}

void QGLCanvas::DrawObjects()
{
	size_t numobjects = objects.size();
	size_t numvertices = vertices.size();
	if(numobjects == 0 || numvertices == 0)
		return;

	glDisable(GL_TEXTURE_2D);

	if(draw->renderMode == QView::RT_WIREFRAME)
		glDisable(GL_DEPTH_TEST);
	else
		glEnable(GL_DEPTH_TEST);

	glCullFace(GL_FRONT);
	glEnable(GL_CULL_FACE);

	// Reset the last texture
	lastTexture = NULL;

	glMatrixMode(GL_PROJECTION);
	glPushMatrix();
	glLoadIdentity();

	wxSize size = GetSize();
	float aspect = float(size.GetWidth())/float(size.GetHeight());
	Game *game = Game::Get();
	gluPerspective(60.0f, aspect, game->GetNearPlane(), game->GetFarPlane());

	glMatrixMode(GL_MODELVIEW);
	glPushMatrix();
	glLoadMatrixf(qooleMatrix);

	// Send the vertices.
	glPushClientAttrib(GL_CLIENT_VERTEX_ARRAY_BIT);

	glEnableClientState(GL_VERTEX_ARRAY);
	glVertexPointer(3, GL_FLOAT, sizeof(GLVertex), &vertices[0].x);

	glEnableClientState(GL_COLOR_ARRAY);
	glColorPointer(3, GL_FLOAT, sizeof(GLVertex), &vertices[0].r);

	glEnableClientState(GL_NORMAL_ARRAY);
	glNormalPointer(GL_FLOAT, sizeof(GLVertex), &vertices[0].nx);

	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
	glTexCoordPointer(2, GL_FLOAT, sizeof(GLVertex), &vertices[0].s);

	// Draw each one of the objects.
	for(size_t i = 0; i < numobjects; i++)
	{
		GLObject &object = objects[i];

		// Load the object model view matrix.
		glPushMatrix();
		glMultTransposeMatrixf((float*)&object.modelViewMatrix);

		// Don't draw points and lines with lighting.
		if(object.mode == GL_POINTS || object.mode == GL_LINES)
			glDisable(GL_LIGHTING);
		else
			glEnable(GL_LIGHTING);

		// Enable the object texture.
		if(draw->renderMode == QView::RT_TEXTURED ||
		   draw->renderMode == QView::RT_SHADED)
		{
			ChangeTexture(object.texture);
		}

		// Draw the object.
		glDrawRangeElementsEXT(object.mode, object.startIndex,
				object.startIndex + object.numVertices, object.numVertices,
				GL_UNSIGNED_SHORT, &indices[object.startIndex]);

		// Pop the object matrix.
		glPopMatrix();
	}

	// Restore the client state.
	glPopClientAttrib();

	// Pop the view matrix.
	glPopMatrix();

	glMatrixMode(GL_PROJECTION);
	glPopMatrix();
}

void QGLCanvas::ChangeTexture(Texture *newTexture)
{
	if(lastTexture == newTexture)
		return;

	lastTexture = newTexture;
	if(newTexture)
	{
		// Enable texturing.
		glEnable(GL_TEXTURE_2D);

		// Upload the texture.
		CheckTexture(newTexture);

		// Set the texture.
		glBindTexture(GL_TEXTURE_2D, newTexture->tInfo);
	}
	else
	{
		// Disable texturing and set an homogenous color.
		glDisable(GL_TEXTURE_2D);
	}
}

void QGLCanvas::CheckTexture(Texture *texture)
{
	if(!texture->tInfo || !glIsTexture(texture->tInfo))
	{
		glGenTextures(1, &texture->tInfo);
		glBindTexture(GL_TEXTURE_2D, texture->tInfo);

		if(texture->bits == 8)
		{
			glTexImage2D(GL_TEXTURE_2D, 0, 3, texture->width, texture->height,
				0, GL_COLOR_INDEX, GL_UNSIGNED_BYTE, texture->mip[0]);
		}
		else if(texture->bits == 16)
		{
			glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB5, texture->width, texture->height, 0,
					GL_RGB, GL_UNSIGNED_SHORT_5_6_5, texture->mip[0]);
		}
		else if(texture->bits == 24)
		{
			GLenum intformat = EXT_texture_compression_s3tc ?
					GL_COMPRESSED_RGB_S3TC_DXT1_EXT : GL_RGB8;
			glTexImage2D(GL_TEXTURE_2D, 0, intformat, texture->width, texture->height,
					0, GL_RGB, GL_UNSIGNED_BYTE, texture->mip[0]);

		}
		else if(texture->bits == 32)
		{
			GLenum intformat = EXT_texture_compression_s3tc ?
					GL_COMPRESSED_RGBA_S3TC_DXT5_EXT : GL_RGBA8;
			glTexImage2D(GL_TEXTURE_2D, 0, intformat, texture->width, texture->height,
					0, GL_RGBA, GL_UNSIGNED_BYTE, texture->mip[0]);
		}
		else
		{
			ASSERT(NULL);
		}

		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	}
}

bool QGLCanvas::ProcessEvent(wxEvent& event)
{
	// If the event is not draw or size, pass it to the parent.
	if(!event.IsKindOf(CLASSINFO(wxPaintEvent)) &&
		!event.IsKindOf(CLASSINFO(wxSizeEvent)) && GetParent())
		GetParent()->ProcessEvent(event);
	return wxEvtHandler::ProcessEvent(event);
}

// QDrawOpenGL
QDrawOpenGL::QDrawOpenGL(wxWindow *wnd)
	: QDraw(wnd)
{
	numBufs = 1;
	wxBoxSizer *sizer = new wxBoxSizer(wxHORIZONTAL);

	// Create the canvas.
	canvas = new QGLCanvas(wnd, this);
	sizer->Add(canvas, 1, wxEXPAND);
	wnd->SetSizer(sizer);
	wnd->SetAutoLayout(true);

	wnd->Layout();

	currentTexture = NULL;
	currentObject = -1;
}

QDrawOpenGL::~QDrawOpenGL()
{
	// Set a null sizer.
	window->SetSizer(NULL);

	// Destroy the canvas.
	canvas->Destroy();
}

void QDrawOpenGL::Size(int cx, int cy)
{
	QDraw::Size(cx, cy);
}

void QDrawOpenGL::Clear(void)
{
	canvas->lines.clear();
	canvas->triangles.clear();
	canvas->normals.clear();
	canvas->vertices.clear();
	canvas->indices.clear();
	canvas->objects.clear();
}

void QDrawOpenGL::Color(int newcolor)
{
	color = newcolor;
}

void QDrawOpenGL::Begin(void)
{
}

void QDrawOpenGL::Line(int x1, int y1, int x2, int y2)
{
	GLLine line;
	line.x1 = (float)x1;
	line.y1 = (float)y1;
	line.x2 = (float)x2;
	line.y2 = (float)y2;
	line.r = (float)pal[color].red / 256.0f;
	line.g = (float)pal[color].green / 256.0f;
	line.b = (float)pal[color].blue / 256.0f;

	canvas->lines.push_back(line);
}

void QDrawOpenGL::Paint(wxDC *pDC)
{
	//canvas->Refresh(false);
	//canvas->Update();
	canvas->Render();
}
void QDrawOpenGL::CopyBuf(int bufNum)
{
}

void QDrawOpenGL::RealizePal(void)
{
	float values[256];
	int i;

	canvas->SetCurrent();
	for(i = 0; i < 256; i++)
		values[i] = (float)pal[i].red / 256.0f;
	glPixelMapfv(GL_PIXEL_MAP_I_TO_R, 256, values);

	for(i = 0; i < 256; i++)
		values[i] = (float)pal[i].green / 256.0f;
	glPixelMapfv(GL_PIXEL_MAP_I_TO_G, 256, values);

	for(i = 0; i < 256; i++)
		values[i] = (float)pal[i].blue / 256.0f;
	glPixelMapfv(GL_PIXEL_MAP_I_TO_B, 256, values);
}

void QDrawOpenGL::Blit(int x, int y, int width, int height,
		wxBitmap &src, int xsrc, int ysrc, int rop, bool useMask)
{
}

void QDrawOpenGL::ZBufInit(void)
{
}

void QDrawOpenGL::ZBufClear(void)
{
}

void QDrawOpenGL::ZBufTriangle(ZPoint zpoint[3])
{
	GLTriangle tri;
	for(int i = 0; i < 3; i++)
	{
		tri.x[i] = zpoint[i].x + orgX;
		tri.y[i] = orgY - zpoint[i].y;
		tri.z[i] = 1.0f / zpoint[i].z;
		if(zbufTex) {
			tri.s[i] = zpoint[i].s / zbufTex->width * tri.z[i];
			tri.t[i] = zpoint[i].t / zbufTex->height * tri.z[i];
		}
	}

	if(bits == 8) {
		tri.r = (float)pal[zbufColor].red / 256.0f;
		tri.g = (float)pal[zbufColor].green / 256.0f;
		tri.b = (float)pal[zbufColor].blue / 256.0f;
	}
	else if(bits == 16)
	{
		tri.r = (float)((((zbufColor >> 11) & 31) << 3) / 256.0f);
		tri.g = (float)((((zbufColor >> 5) & 63) << 2) / 256.0f);
		tri.b = (float)((((zbufColor >> 0) & 31) << 3) / 256.0f);
	}
	else
	{
		ASSERT(NULL);
	}

	if(renderMode == QView::RT_TEXTURED ||
		renderMode == QView::RT_SHADED)
	{
		float v1[3], v2[3];
		v1[0] = tri.x[0] - tri.y[0];
		v1[1] = tri.x[1] - tri.y[1];
		v1[2] = tri.x[2] - tri.y[2];

		v2[0] = tri.y[0] - tri.z[0];
		v2[1] = tri.y[1] - tri.z[1];
		v2[2] = tri.y[2] - tri.z[2];

		GLNormal normal;
		normal.nf[0] = v1[1]*v2[2] - v1[2]*v2[1];
		normal.nf[1] = v1[2]*v2[0] - v1[0]*v2[2];
		normal.nf[2] = v1[0]*v2[1] - v1[1]*v2[0];

		float length= (float)sqrt((normal.nf[0] * normal.nf[0]) +
							(normal.nf[1] * normal.nf[1]) +
							(normal.nf[2] * normal.nf[2]));

		if(length == 0.0f)
			length = 1.0f;

		normal.nf[0] /= length;
		normal.nf[1] /= length;
		normal.nf[2] /= length;
		canvas->normals.push_back(normal);
	}

	tri.texture = zbufTex;

	canvas->triangles.push_back(tri);
}

void QDrawOpenGL::ZBufRender(void)
{
}

// New hardware based rendering.
bool QDrawOpenGL::UseHardware() const
{
	return true;
}

bool QDrawOpenGL::SameBits() const
{
	return true;
}

void QDrawOpenGL::UpdateBits(int bits)
{
	this->bits = bits;
}

void QDrawOpenGL::BeginObject(Object *object, PrimitiveType mode)
{
	ASSERT(object);
	ASSERT(currentObject == -1);

	GLObject glObject;
	glObject.startIndex = canvas->vertices.size();
	glObject.numVertices = 0;
	glObject.texture = currentTexture;
	glObject.modelViewMatrix = object->GetTransformation();

	switch(mode)
	{
	default:
	case PT_POINTS:
		glObject.mode = GL_POINTS;
		break;
	case PT_LINES:
		glObject.mode = GL_LINES;
		break;
	case PT_TRIANGLES:
		glObject.mode = GL_TRIANGLES;
		break;
	case PT_TRIANGLE_FAN:
		glObject.mode = GL_TRIANGLE_FAN;
		break;
	case PT_TRIANGLE_STRIP:
		glObject.mode = GL_TRIANGLE_STRIP;
		break;

	}

	currentObject = canvas->objects.size();
	canvas->objects.push_back(glObject);
}

void QDrawOpenGL::EndObject()
{
	ASSERT(currentObject >= 0);
	ASSERT(canvas->objects.size() > 0);
	currentObject = -1;
}

void QDrawOpenGL::ChangeTexture(FaceTex *faceTex)
{
	Texture *newTexture = faceTex ? faceTex->GetTexture() : NULL;
	if(newTexture == currentTexture)
		return;

	currentTexture = newTexture;
	if(currentObject == -1)
		return;

	// TODO: Transparently create a new object.
}

void QDrawOpenGL::SendVertex(const TriVertex &vertex)
{
	ASSERT(currentObject >= 0);
	ASSERT(canvas->objects.size() > 0);
	GLObject &glObject = canvas->objects[currentObject];

	GLVertex glVertex;
	glVertex.x = vertex.x;
	glVertex.y = vertex.y;
	glVertex.z = vertex.z;
	glVertex.r = vertex.r;
	glVertex.g = vertex.g;
	glVertex.b = vertex.b;
	glVertex.nx = vertex.nx;
	glVertex.ny = vertex.ny;
	glVertex.nz = vertex.nz;
	glVertex.s = vertex.s;
	glVertex.t = vertex.t;
	canvas->indices.push_back(canvas->indices.size());
	canvas->vertices.push_back(glVertex);
	glObject.numVertices++;
}
